import java.io.*;
import java.io.File;  
import java.io.FileReader;  
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;



public class Main {
	int n1;
	int n2;
    int n3;
    String[] attrNames;
    String f10[];
    String s3[];
    int c[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int f[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    int ml=0;
    int mc=0;
    int mf=0;
   
    double minSup;
        public static void main(String args[]){
                          
              String filePath20="src/main/resources/output.txt";
              HashMap<String, Integer> attr2Num = new HashMap<>();  
              HashMap<Integer, String> num2Attr = new HashMap<>(); 
              String filePath="src/main/resources/input1.txt";
              double minSup=0.002285;
              int hashTableSize=1000000;
              Context context=new Context();
              AlgoCharm_Bitset charm=new AlgoCharm_Bitset();
              Main demo = new Main();
              Output demo20=new Output();
              demo.readRDBMSData(filePath,context,attr2Num,num2Attr);		
              charm.runAlgorithm(context,minSup,hashTableSize,num2Attr);
              demo.printFItems(charm.closedItemsets,num2Attr,demo.n1,demo.n2,demo.n3,minSup);
              String[] attrNames=new String[demo.n2+1];
              demo20.output20(filePath20,charm.closedItemsets,num2Attr,demo.attrNames,demo.n2);
        }

         /** 
	         *读关系表中的数据，转化为事务数据 ，并导入context
	     *  
	     * @param filePath 
	     */  

        public  void readRDBMSData(String filePath,Context context,HashMap<String, Integer> attr2Num,
	    		HashMap<Integer, String> num2Attr) {  
	        String str;  
	        // 属性名称行 
	       
	        String[] temp;  
	        String[] newRecord;  
	        ArrayList<String[]> datas = null;  
	        ArrayList<String[]> transactionDatas;
	        datas = readLine(filePath);  
	        n3=datas.size()-1;
	        //  获取首行  
	        attrNames = datas.get(0); 
            n2=attrNames.length-1; 
	        transactionDatas = new ArrayList<>();  
	  
	        // 去除首行数据  
	        for (int i = 1; i < datas.size(); i++) {  
	            temp = datas.get(i);  
	  
	            // 过滤掉最后的类标列
	            for (int j = 0; j < temp.length-1; j++) {  
	                str = "";  
	                // 采用“属性名+属性值+类标”的形式避免数据的重复， 并带类标约束
	                str = attrNames[j] + ":" + temp[j]+ ":" + temp[temp.length-1];  
	                temp[j] = str;  
	            }  
	  
	            newRecord = new String[attrNames.length - 1];  
	            System.arraycopy(temp, 0, newRecord, 0, attrNames.length - 1);  
	            transactionDatas.add(newRecord); 
	            
	        }  
	        
	        // 属性值替换成数字的形式
	        attributeReplace(transactionDatas,attr2Num,num2Attr);  
	        // 将事务数据转到context中做统一处理
	        for(int i=0;i<transactionDatas.size();i++){ 
		        		
                             context.addObject(transactionDatas.get(i));
                             
            }
	     }  

         /** 
	         * 从文件中逐行读数据
	     *  
	     * @param filePath 
	         *  数据文件地址  
	     * @return 
	     */  	   
        private  ArrayList<String[]> readLine(String filePath) {  
	        File file = new File(filePath);  
	        ArrayList<String[]> dataArray = new ArrayList<String[]>();  
	  
	        try {  
	            BufferedReader in = new BufferedReader(new FileReader(file));  
	            String str;  
	            String[] tempArray;  
	            while ((str = in.readLine()) != null) {  
	                tempArray = str.split(" ");  
	                dataArray.add(tempArray);  
	            }  
	            in.close();  
	        } catch (IOException e) {  
	            e.getStackTrace();  
	        }  
	  
	        return dataArray;  
	    }


	  
	    /** 
	         * 属性值的替换，替换成数字的形式，以便进行频繁项的挖掘 
	     */  
        private  void attributeReplace(ArrayList<String[]> transactionDatas,HashMap<String, Integer> attr2Num,
	    		HashMap<Integer, String> num2Attr) {  
	        int currentValue = 1;  
	        String s;  
	        // 属性名到数字的映射图  
            //	        attr2Num = new HashMap<>();  
            //	        num2Attr = new HashMap<>();  
	  
	        // 按照1列列的方式来，从左往右边扫描  
	        for (int j = 0; j < transactionDatas.get(0).length; j++) {  
	            for (int i = 0; i < transactionDatas.size(); i++) {  
	                s = transactionDatas.get(i)[j];  
	  
	                if (!attr2Num.containsKey(s)) {  
	                    attr2Num.put(s, currentValue);  
	                    num2Attr.put(currentValue, s);  
	  
	                    transactionDatas.get(i)[j] = currentValue + "";  
	                    //System.out.println("currentValue :"+currentValue+" n:"+num2Attr.get(currentValue)+" "+" i :"+i+" j:"+j);
	                    currentValue++; 
	                } else {  
	                    transactionDatas.get(i)[j] = attr2Num.get(s) + "";  
	                }  
	            }  
	        }  
//	        System.out.println(num2Attr.get(1));
            n1=currentValue;
	    }  
	  


	    /** 
	     * 输出频繁闭合项集
	     */  
        private  void printFItems(Itemsets closedItemsets,HashMap<Integer, String> num2Attr,int n1,int n2,int n3,double minSup) {  
	          
	       int l=closedItemsets.getLevels().size()-1;
	       System.out.println("支持度阈值："+minSup+"；实例数："+n3+"；属性数："+n2+ "；项数："+n1);
           for (int k=1; k<=l;k++){
              for(Itemset i:closedItemsets.getLevels().get(k)){
                 c[k-1]++;
                 if(i.cardinality>=f[k-1]){
                    f[k-1]=i.cardinality;
                 }
              }
              System.out.println(k+"项集：");
              System.out.println("数量："+c[k-1]+"；最大频次："+f[k-1]);
           }
           for (int k=1;k<=l;k++){
              ml=ml+k;  mc=mc+c[k-1];  mf=mf+f[k-1];
           }
           double ml1=(double)ml/l;
           double ml2=(double)ml1/n2;                          
           double mc1=(double)mc/l;
           double mc2=(double)mc1/n3;
           double mf1=(double)mf/l;
           double mf2=(double)mf1/n3;
           System.out.println("模式总数量："+mc);
           System.out.println("模式平均长度："+ml1+"；平均数量："+mc1+"；平均频次："+mf1);
           System.out.println("模式与实例长度比："+ml2+"；数量比："+mc2+"；频次比："+mf2);
           
            }
  }




